package com.example.stock.service.impl;

import com.example.stock.controller.dto.WeekPctStatDTO;
import com.example.stock.controller.vo.StockInfoVO;
import com.example.stock.controller.vo.WeekDetailVO;
import com.example.stock.mapper.WeekDetailMapper;
import com.example.stock.model.GBSta;
import com.example.stock.model.WeekDetail;
import com.example.stock.service.GBStaService;
import com.example.stock.service.StockService;
import com.example.stock.service.WeekDataService;
import com.example.stock.util.DateUtil;
import com.example.stock.util.NumberUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

@Log4j2
@Service
public class WeekDataServiceImpl implements WeekDataService {

    @Autowired
    WeekDetailMapper weekDetailMapper;

    GBStaService gbStaService;

    StockService stockService;

    @Autowired
    public void setGbStaService(GBStaService gbStaService) {
        this.gbStaService = gbStaService;
    }

    @Autowired
    public void setStockService(@Lazy StockService stockService) {
        this.stockService = stockService;
    }

    private final Map<String, List<WeekDetail>> weekDataGroupByStock = new HashMap<>();

    @Override
    public List<WeekDetail> getWeekRawData(String stock) {
        if (weekDataGroupByStock.containsKey(stock)) {
            return weekDataGroupByStock.get(stock);
        }
        List<WeekDetail> weekDetailByStock = weekDetailMapper.getWeekDetailByStock(stock);
        weekDataGroupByStock.put(stock, weekDetailByStock);

        return weekDetailByStock;
    }

    @Override
    public List<WeekDetail> getWeekRawDataByDate(String date) {
        return weekDetailMapper.getWeekDetailByDate(date);
    }

    @Override
    public List<WeekPctStatDTO> getWeekMeanGt(String date) {
        return format(weekDetailMapper.getWeekMeanGt(date));
    }

    @Override
    public List<WeekDetail> getWeekPctMostDecrease(int num) {
        return weekDetailMapper.getWeekPctMostDecrease(num);
    }

    @Override
    public List<WeekDetail> getWeekMostPctSum() {
        return weekDetailMapper.getWeekMostPctSum();
    }

    private Map<String, WeekDetail> curWeekDetailMap;

    @Override
    public WeekDetail getCurrentWeekDetail(String stock) {
        if (curWeekDetailMap == null) {
            List<WeekDetail> weekRawDataByDate = getWeekRawDataByDate(getWeekPctStatKeys().getFirst());
            curWeekDetailMap = weekRawDataByDate.stream().collect(Collectors.toMap(WeekDetail::getStock, i -> i));
        }
        return curWeekDetailMap.get(stock);
    }

    @Override
    @Cacheable(value = "getWeekData", key = "#stock")
    public List<WeekDetailVO> getWeekData(String stock) {

        List<WeekDetail> weekDetails = weekDetailMapper.getWeekDetailByStock(stock);
        if (weekDetails == null) {
            return null;
        }

        // lambda 中不能直接使用变量
        Double lpClose[] = {0.0};

        // 计算 10 分位点下跌
        List<WeekDetailVO> collect = weekDetails.stream().map(weekDetail -> {
            WeekDetailVO weekDetailVO = new WeekDetailVO();
            BeanUtils.copyProperties(weekDetail, weekDetailVO);

            // 分位点大于10的不计算
            if (weekDetail.getLp() > 10) {
                lpClose[0] = 0.0;
                return weekDetailVO;
            }
            // 第一个分位点低于 10 的记录
            if (lpClose[0] == 0.0) {
                lpClose[0] = weekDetail.getClose();
            }

            weekDetailVO.setLpDecrease(
                    NumberUtil.calPct(weekDetail.getClose(), lpClose[0])
            );
            return weekDetailVO;
        }).collect(toList());

        // 计算 300 日线下跌与上涨
        Double yearLineClose[] = {0.0, 0.0};

        // 下穿300日线
        collect.forEach(weekDetailVO -> {
            int pre = collect.indexOf(weekDetailVO) - 1;
            if(pre >= 0 && collect.get(pre).getDisPct() >= 0 && weekDetailVO.getDisPct() < 0) {
                yearLineClose[0] = weekDetailVO.getClose();
            }
            if (weekDetailVO.getDisPct() > 0) {
                return;
            }
            if (yearLineClose[0] == 0.0) {
                return;
            }

            double yearLineDecrease = NumberUtil.calPct(weekDetailVO.getClose(), yearLineClose[0]);
            weekDetailVO.setYearLineDecrease(yearLineDecrease);
        });

        // 上穿300日线
        collect.forEach(weekDetailVO -> {
            // 上穿300日线
            int pre = collect.indexOf(weekDetailVO) - 1;
            if(pre >= 0 && collect.get(pre).getDisPct() < 0 && weekDetailVO.getDisPct() >= 0) {
                yearLineClose[1] = weekDetailVO.getClose();
            }
            if (weekDetailVO.getDisPct() < 0) {
                return;
            }
            if (yearLineClose[1] == 0.0) {
                return;
            }
            double yearLineIncrease = NumberUtil.calPct(weekDetailVO.getClose(), yearLineClose[1]);
            weekDetailVO.setYearLineDecrease(yearLineIncrease);
        });

        return collect;
    }

    @Override
    public Map<String, List<WeekDetail>> getWeekRawData(List<String> stocks) {
        if (Objects.isNull(stocks) || stocks.isEmpty()) {
            return null;
        }

        Map<String, List<WeekDetail>> map = new LinkedHashMap<>();
        stocks.forEach(stock -> {
            List<WeekDetail> weekData = getWeekRawData(stock);
            if (!Objects.isNull(weekData)) {
                map.put(stock, weekData);
            }
        });
        return map;
    }

    // 周涨跌 Key
    @Override
    public List<String> getWeekPctStatKeys() {
        return getWeekPctStatKeys(60);
    }

    @Override
    public List<String> getWeekPctStatKeys(int num) {
        return weekDetailMapper.getDates().stream()
                .sorted(Comparator.comparing(String::toString).reversed())
                .limit(num)
                .toList();
    }

    @Override
    @Cacheable(value = "getWeekPctStatList", key = "#week")
    public List<WeekPctStatDTO> getWeekPctStatList(String week) {
        return format(getWeekRawDataByDate(week));
    }

    private List<WeekPctStatDTO> format(List<WeekDetail> weekDetails) {
        if (weekDetails == null || weekDetails.isEmpty()) {
            return null;
        }

        List<WeekPctStatDTO> ret = new ArrayList<>();

        weekDetails.forEach(i -> {
            WeekPctStatDTO weekPctStatDTO = new WeekPctStatDTO();
            BeanUtils.copyProperties(i, weekPctStatDTO);

            // disDuration
            List<GBSta> gb60WStaByStock = gbStaService.getGBStaByStock(i.getStock(), GBStaServiceImpl.GB_60W_K);
            int i1;
            if (gb60WStaByStock != null && !gb60WStaByStock.isEmpty()) {
                i1 = DateUtil.calWeekDataDuration(i.getDate(), gb60WStaByStock.getLast().getDate()) + 1;
            } else {
                i1 = getWeekRawData(i.getStock()).size();
            }
            if (i.getDisPct() < 0) i1 *= -1;
            weekPctStatDTO.setDisDuration(i1);

            // 个股信息
            StockInfoVO stockInfo = stockService.getStockInfo(i.getStock());
            weekPctStatDTO.setTag(stockInfo.getTag());
            weekPctStatDTO.setRank(stockInfo.getRank());

            ret.add(weekPctStatDTO);
        });

        return ret;
    }
}
